<script setup lang="ts">
import {
  ArrowLeftBold,
  ArrowRightBold,
  Stopwatch,
} from '@element-plus/icons-vue'
import Calendar from './utils/Calendar'
import DateClass from './utils/DateClass'
import ViewCalendarItem from './view-calendar-item.vue'
import type {
  ActionType,
  ViewCalendarProps,
  ViewCalendarScope,
} from './type'
import { clockFactory } from './utils/func'
import { formatTime } from '@/utils'
import './style.scss'

const props = withDefaults(
  defineProps<ViewCalendarProps>(),
  {
    worksTime: () => [],
    holidaysTime: () => [],
    dateBadge: () => ({}),
    spanData: () => ({}),
    span: false,
  },
)
const emits = defineEmits<{
  getDate: [data: ViewCalendarScope]
  changeMonth: [data: ViewCalendarScope]
  change: []
}>()
// import { useCurrentElement  } from '@vueuse/core';
// ------------------use------------------
// #region
defineSlots<{
  /** ## 头部操作区域 */
  header: () => void
  /** ## 标题 */
  title: () => void
  /** ## 自定义内容 */
  cell: (props: ViewCalendarScope) => void
}>()
/** 当前时间 */
const time = defineModel<string>('time', {
  default: formatTime(Date.now(), 'YYYY-MM-DD'),
  get(v: string) {
    return formatTime(v || Date.now(), 'YYYY-MM-DD')
  },
})
/** 获取当前组件dom */
// const viewCalendarRef = useCurrentElement();
const [spanModalPosition, setSpanModalPosition] = useState({
  x: 0,
  y: 0,
})
const [isSpanModal, setIsSpanModal] = useState(false)
const [spanTarget, setSpanTarget]
  = useState<MouseEvent | null>(null)
// #endregion
// ------------------静态变量------------------
// #region
const headerData = Calendar.title()
const spanTitleHeight = 30
const spanTitleSize = 14
const spanTitleGap = 4
// #endregion
// ------------------动态变量------------------
// #region

// #endregion
// ------------------ref-----------
// #region
const year = ref(new Date().getFullYear())
const month = ref(new Date().getMonth() + 1)
const day = ref(new Date().getDate())
const viewCalendarBodyDayRef = ref<HTMLElement>()
const spanConfig = ref({
  seat: 0, // 占位数量
  height: 0, // 单个元素高度
  rowHeight: '1fr',
})

// const spanModalPosition = ref({
//   x: 0,
//   y: 0
// });
// #endregion
// ------------------reactive------
// #region

// #endregion
// ------------------computed------
// #region
const bodyData = computed(() =>
  Calendar.table(
    DateClass.changeTimeStr(time.value),
    props.worksTime,
    props.holidaysTime,
  ),
)
const currentSpsnData = computed(
  () => props.spanData[time.value],
)
// #endregion
// ------------------生命周期------------------
// #region

// #endregion
// ------------------内置方法---------------------
// #region
watch(
  () => spanConfig.value.height,
  async () => {
    // await nextTick();
    // computedSpanPosition();
    await nextTick()
    computedSpanPosition()
  },
)
// #endregion
// ------------------方法---------------------
// #region
function changeDate(data: ViewCalendarScope) {
  time.value = data.date
  day.value = +data.date.split('-').at(-1)!
  emits('getDate', data)
}
function changeMonth(num: number) {
  if (month.value + num >= 0) {
    let yearAdd = Number.parseInt(
      String(Math.abs(month.value + num) / 12),
    )
    if (month.value + num === 12) {
      yearAdd = 0
    }
    year.value = year.value + yearAdd

    const monthAdd = month.value + num - yearAdd * 12
    month.value = monthAdd
    day.value = 1
  }
  if (month.value + num < 0) {
    const yearAdd
      = Number.parseInt(String(Math.abs(month.value + num) / 12))
      + 1

    year.value = year.value - yearAdd
    month.value
      = yearAdd * 12
      + (month.value === 0 ? 1 : month.value)
      + num
  }
  time.value = `${year.value}-${clockFactory(
    month.value,
  )}-${clockFactory(day.value)}`
  emits('change')
}
async function changeToNow() {
  const date = DateClass.getCurrent()

  year.value = date[0]!
  month.value = date[1]!
  day.value = date[2]!
  time.value = `${year.value}-${clockFactory(
    month.value,
  )}-${clockFactory(day.value)}`
  emits('change')
}

function handleChangeMonth(
  action: ActionType,
  data: ViewCalendarScope,
) {
  changeMonth(action === 'next' ? 1 : -1)
  emits('changeMonth', data)
}

async function setCurrentSpanCell(
  node?: MouseEvent,
  data?: ViewCalendarScope,
) {
  if (!node || !data) {
    setIsSpanModal(false)
    return
  }
  setSpanTarget(node)
  await nextTick()
  await computedSpanPosition()
  computedSpanHeight()
  spanConfig.value.seat = new Date(data.date).getDay()
  setIsSpanModal(true)
}
function handleSpanTitle(i: number) {
  if (!spanTarget.value || !currentSpsnData.value)
    return []
  const { width } = (spanTarget.value
    .target as HTMLElement)!.getBoundingClientRect()

  const count = Math.floor(width / spanTitleSize)
  const arr: string[] = []
  currentSpsnData.value.data.forEach((item) => {
    if (item.span === 0) {
      if (i === 1)
        arr.push(item.title)
    }
    else {
      if (i > item.span + 1) {
        // arr.push('');
      }
      else {
        arr.push(
          item.title.slice((i - 1) * count, i * count),
        )
      }
    }
  })
  return arr
}
async function computedSpanPosition() {
  const { top: t0 }
    = viewCalendarBodyDayRef.value!.getBoundingClientRect()
  await nextTick()
  const { top: t1 } = (spanTarget.value!
    .target as HTMLElement)!.getBoundingClientRect()
  console.log(viewCalendarBodyDayRef.value!.scrollTop)

  setSpanModalPosition({
    x: 0,
    y: t1 - t0 + viewCalendarBodyDayRef.value!.scrollTop,
    // y: (spanTarget.value!.target as HTMLElement).offsetTop
  })
}
function computedSpanHeight() {
  // 数量
  const i = currentSpsnData.value?.data?.length ?? 0
  // 计算大致高度
  const m = i * spanTitleHeight + (i - 1) * spanTitleGap
  // 根据父亲计算
  const n = viewCalendarBodyDayRef.value!.clientHeight / 6
  const max = Math.max(n, m)
  spanConfig.value.rowHeight = `${max}px`
  spanConfig.value.height = max
}
defineExpose({
  changeMonth,
  changeToNow,
})
// #endregion
</script>

<template>
  <div
    class="flex-direction height-fill width-fill padding-sm view-calendar box-border flex"
    :class="[{ span }]"
  >
    <!-- header -->
    <div
      class="flex-incompressible align-center view-calendar-header padding-bottom-sm box-border flex"
    >
      <slot name="header">
        <div
          class="align-center c-pointer view-calendar-header__left relative flex"
        >
          <slot name="title">
            <el-date-picker
              v-model="time"
              value-format="YYYY-MM-DD"
              type="date"
            />
            <el-icon class="fs-20 margin-right-xs">
              <Stopwatch />
            </el-icon>
            <div class="fs-20 view-calendar-header__time">
              {{ formatTime(new Date(time), 'YYYY-MM-DD') }}
            </div>
            <div class="view-calendar-header__week fs-14">
              {{
                DateClass.getWeek(new Date(time).getDay())
              }}
            </div>
          </slot>
        </div>
        <div
          class="margin-left-auto view-calendar-header__right"
        >
          <el-button-group>
            <el-button
              :icon="ArrowLeftBold"
              size="small"
              @click="changeMonth(-1)"
            >
              上个月
            </el-button>
            <el-button size="small" @click="changeToNow()">
              回到今日
            </el-button>
            <el-button size="small" @click="changeMonth(1)">
              下个月
              <el-icon>
                <el-icon><ArrowRightBold /></el-icon>
              </el-icon>
            </el-button>
          </el-button-group>
        </div>
      </slot>
    </div>
    <!-- body -->
    <div
      class="flex-fillRemaining flex-direction overflow view-calendar-body relative box-border flex"
    >
      <ul
        class="flex-incompressible view-calendar-body__week"
      >
        <li
          v-for="(item, index) in headerData"
          :key="index"
        >
          {{ item }}
        </li>
      </ul>
      <div
        ref="viewCalendarBodyDayRef"
        class="flex-fillRemaining view-calendar-body__day relative grid"
        :style="{
          '--view-calendar-row-height': spanConfig.rowHeight,
        }"
      >
        <div
          v-for="(item, index) in bodyData"
          :key="index"
          class="view-calendar-body__row"
        >
          <!-- 横向瀑布流；用作排班跨行跨列 -->
          <!-- <div
            v-if="span"
            class="view-calendar-body__waterfall absolute"
          ></div> -->
          <div
            v-for="(col, colIdx) in item"
            :key="colIdx"
            class="view-calendar-body__col"
          >
            <ViewCalendarItem
              :data="col"
              :time="time"
              :set-current-span-cell="setCurrentSpanCell"
              @change-target-date="changeDate"
              @change-month="handleChangeMonth"
            >
              <slot name="cell" v-bind="col" />
            </ViewCalendarItem>
          </div>
        </div>
        <!-- 标记-显示当前月份 -->
        <div class="view-calendar-body__mark">
          {{ time.split('-')[1] }}
        </div>
        <!-- 跨行 -->
        <template v-if="span && currentSpsnData">
          <Transition
            leave-active-class="animate__animated context-menu-animate animate__faster  animate__fadeOut"
            enter-active-class="animate__animated context-menu-animate animate__faster  animate__fadeIn"
          >
            <div
              v-show="isSpanModal"
              class="width-fill view-calendar-body__span absolute"
              :style="{
                'height': `${
                  Math.ceil(
                    (spanConfig.seat
                      + currentSpsnData!.maxSpan)
                      / 7,
                  ) * spanConfig.height
                }px`,
                'top': `${spanModalPosition.y}px`,
                'left': `${spanModalPosition.x}px`,
                '--item-height': `${spanConfig.height}px`,
                '--item-title-height': `${spanTitleHeight}px`,
                '--item-size': `${spanTitleSize}px`,
                '--item-gap': `${spanTitleGap}px`,
              }"
            >
              <!-- 占位div -->
              <div
                v-for="i in spanConfig.seat"
                :key="i"
                class="seat"
              />
              <div
                v-for="i in (currentSpsnData!.maxSpan + 1)"
                :key="i"
                class="overflow flex-direction box-border flex"
              >
                <template
                  v-for="(j, index) in handleSpanTitle(i)"
                  :key="j"
                >
                  <template
                    v-if="i === 1 && i === currentSpsnData.data[index]!.span + 1"
                  >
                    <el-tooltip
                      :content="j"
                      placement="top"
                    >
                      <p
                        :class="[
                          {
                            first: i === 1,
                            last:
                              i === currentSpsnData.data[index]!.span + 1,
                          },
                        ]"
                        class="box-border"
                      >
                        {{ j }}
                      </p>
                    </el-tooltip>
                  </template>
                  <p
                    v-else
                    :class="[
                      {
                        first: i === 1,
                        last:
                          i === currentSpsnData.data[index]!.span + 1,
                      },
                    ]"
                    class="box-border"
                  >
                    {{ j }}
                  </p>
                </template>
              </div>
            </div>
          </Transition>
        </template>
      </div>
    </div>
  </div>
</template>

<style lang="scss">
//------------------组件样式------------------
//-------------样式穿透-------------
</style>
